/*
 *   Copyright 2011 Joshua Swank
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

package name.swank.language;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import com.google.common.base.Preconditions;

public class ProductionRule
{
    public final static class Context
    {
	private final SymbolSequence prefix_, suffix_;

	public Context()
	{
	    this(null, null);
	}

	public Context(SymbolSequence prefix, SymbolSequence suffix)
	{
	    prefix_ = (prefix != null) ? prefix : new SymbolSequence();
	    suffix_ = (suffix != null) ? suffix : new SymbolSequence();
	}

	public SymbolSequence format(SymbolSequence content)
	{
	    List<Symbol> symbols = new ArrayList<Symbol>();

	    symbols.addAll(prefix_.asList());

	    if (content != null)
		symbols.addAll(content.asList());

	    symbols.addAll(suffix_.asList());

	    return new SymbolSequence(symbols);
	}

	public boolean isEmpty()
	{
	    return prefix_.isEmpty() && suffix_.isEmpty();
	}
    }

    private final SymbolSequence head_, body_;
    private final Symbol nonterminal_;

    public ProductionRule(Symbol head)
    {
	this(head, null, null);
    }

    public ProductionRule(Symbol head, Context headContext)
    {
	this(head, headContext, null);
    }

    public ProductionRule(Symbol head, Context headContext, SymbolSequence body)
    {
	Preconditions.checkNotNull(head);

	nonterminal_ = head;
	head_ = (headContext != null) ? headContext.format(new SymbolSequence(head)) : new SymbolSequence(head);
	body_ = (body != null) ? body : new SymbolSequence();
    }

    public ProductionRule(Symbol head, SymbolSequence body)
    {
	this(head, null, body);
    }

    public final SymbolSequence getBody()
    {
	return body_;
    }

    public final SymbolSequence getHead()
    {
	return head_;
    }

    public final Symbol getNonterminal()
    {
	return nonterminal_;
    }

    Set<Symbol> getNonterminalSymbols()
    {
	Set<Symbol> nonterminals = new HashSet<Symbol>();

	nonterminals.add(nonterminal_);

	return nonterminals;
    }

    final Set<Symbol> getSymbols()
    {
	HashSet<Symbol> symbols = new HashSet<Symbol>();

	symbols.addAll(head_.asList());
	symbols.addAll(body_.asList());

	return symbols;
    }

    Set<Symbol> getTerminalSymbols()
    {
	return new HashSet<Symbol>();
    }
}
